package com.xbongbong.paas.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasProcessRelatedDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.VisibleRulePoJo;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.model.PaasProcessRelatedDataModel;
import com.xbongbong.paas.pojo.ProductFieldPojo;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.InstockErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.BusinessProductEntity;
import com.xbongbong.saas.domain.entity.BusinessUnitProductEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductStockEntity;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.enums.FormConfigEnum;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.InventoryEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.ProductionOrderEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseEnum;
import com.xbongbong.saas.enums.business.TransferEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.help.BatchKeyHelp;
import com.xbongbong.saas.help.RelativeProductHelp;
import com.xbongbong.saas.help.SaasFormHelp;
import com.xbongbong.saas.help.SaasProductHelp;
import com.xbongbong.saas.help.ValidateLinkProductHelp;
import com.xbongbong.saas.help.workflow.ProductValidateHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.saas.model.InstockModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductStockModel;
import com.xbongbong.saas.model.ProductWarehouseModel;
import com.xbongbong.saas.model.ReturnedPurchaseProductModel;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.util.ProductUtil;
import com.xbongbong.util.SaasLinkProductUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author haibin.zhang
 * @version v1.0
 * @date 2019/9/29 9:14
 * @since v1.0
 */
@Component
public class FormDataValidateProductHelp extends ValidateLinkProductHelp {

    private static final Logger LOG = LoggerFactory.getLogger(FormDataValidateProductHelp.class);

    @Resource
    private EsHelper esHelper;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private ReturnedPurchaseProductModel returnedPurchaseProductModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private ProGetHelp proGetHelp;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private SaasFormHelp saasFormHelp;
    @Resource
    private RelativeProductHelp relativeProductHelp;
    @Resource
    private ProductStockModel productStockModel;
    @Resource
    private PaasProcessRelatedDataModel paasProcessRelatedDataModel;
    @Resource
    private ProductWarehouseModel productWarehouseModel;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private FormConfigModel formConfigModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private SaasProductHelp saasProductHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ProductValidateHelp productValidateHelp;
    @Resource
    private InstockModel instockModel;
    @Resource
    private OutstockModel outstockModel;

    /**
     * 校验产品存在合法
     * @param corpid 公司id
     * @param productIdLit 产品idList
     * @throws XbbException
     */
    public Map<Long, String> productExit(String corpid, List<Long> productIdLit) throws XbbException {
        return saasProductHelp.productExit(corpid, productIdLit);
    }

    /**
     * 校验产品存在合法
     * @param corpid 公司id
     * @param productIdLit 产品idList
     * @throws XbbException
     */
    public Map<Long, String> productExitContract(JSONArray productList, String corpid, List<Long> productIdLit) throws XbbException {
        return saasProductHelp.productExitContract(productList, corpid, productIdLit);
    }


    /**
     * 用户关联产品保存
     * @param corpid
     * @param productList
     * @return
     * @throws XbbException
     */
    public Map<Long,PaasFormDataEntityExt> product2saveMap(String corpid, JSONArray productList) throws XbbException {
        return saasProductHelp.product2saveMap(corpid, productList);
    }





    /**
     * 查询未入库产品
     * @param corpid
     * @param refId
     * @param type
     * @return
     * @throws XbbException
     */
    public List<BusinessProductEntity> searchUnInstockProduct(String corpid, Long refId, Integer type, boolean needThrow) throws XbbException {
        List<InstockProductEntity> instockProductEntityList = instockProductModel.getUpStreamProduct(corpid,type,refId);
        boolean needMerge = false;
        for (InstockProductEntity entity : instockProductEntityList){
            if (Objects.isNull(entity.getRefProductId())) {
                needMerge = true;
                break;
            }
        }
        Map<String,Double> businessNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> productIdList = new ArrayList<>();
        for (InstockProductEntity entity : instockProductEntityList){
            if (needMerge) {
                Double num = businessNumMap.getOrDefault(entity.getProductId().toString(),0D);
                num = Arith.add(entity.getProductNum(), num);
                businessNumMap.put(entity.getProductId().toString(),num);
            } else {
                Double num = entity.getProductNum();
                String key = entity.getProductId() + "_" + entity.getRefProductId();
                businessNumMap.put(key,Arith.add(businessNumMap.getOrDefault(key,0D), num));
            }
        }

        List<BusinessProductEntity> businessProductEntityList = relativeProductHelp.getInstockRelyBusinessProduct(corpid,refId,type,needMerge);
        businessProductEntityList.forEach(businessProductEntity -> {
            if (Objects.nonNull(businessProductEntity)) {
                productIdList.add(businessProductEntity.getProductId());
            }
        });
        Map<Long, ProductEntityExt> productMap = new HashMap<>(1 << 1);
        if (CollectionsUtil.isNotEmpty(productIdList)) {
            productMap = productModel.getProductMapByIds(corpid, productIdList, DelEnum.NORMAL.getDel(), Arrays.asList(StringConstant.SAAS_LINK_BUSINESS_ID, ProductEnum.getAttrConnectData(ProductEnum.ENABLE_SERIAL_NUMBER)));
        }
        // TODO 审批中数据校验 + 抛出错误
        InstockTypeEnum instockTypeEnum = InstockTypeEnum.getByCode(type);
        if (Objects.equals(instockTypeEnum, InstockTypeEnum.PURCHASE_INSTOCK) || Objects.equals(instockTypeEnum, InstockTypeEnum.TRANSFER_INSTOCK)) {
            boolean isTransfer = Objects.equals(instockTypeEnum, InstockTypeEnum.TRANSFER_INSTOCK);
            Map<String,Double> processNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 是否开启了工作流
            boolean isOpenWorkflow = commonHelp.isOpenWorkFlow(corpid);
            if (!isOpenWorkflow) {
                List<PaasProcessRelatedDataEntity> processDataList = paasProcessRelatedDataModel.getByRefIdAndBusinessType(refId, instockTypeEnum.getStockBusinessType(), corpid);
                processDataList.forEach(item -> {
                    String key = isTransfer ? item.getFourthRefId().toString() : item.getFourthRefId() + "_" + item.getSecondRefId();
                    Double num = processNumMap.getOrDefault(key, 0D);
                    num = Arith.add(num, item.getValue());
                    processNumMap.put(key, num);
                });
            } else {
                List<PaasFormDataEntityExt> instockList = instockModel.findInstockList(corpid, type, refId,
                        Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()), Arrays.asList(FieldTypeEnum.DATAID.getAlias()));
                List<Long> instockIdIn = new ArrayList<>();
                instockList.forEach(item -> instockIdIn.add(item.getDataId()));

                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", corpid);
                param.put("refId", refId);
                param.put("type", type);
                param.put("del", 0);
                param.put("orderByStr", "sort");
                param.put("intoWarehouseIdIn", instockIdIn);
                List<InstockProductEntity> processInstockProductList = instockProductModel.findEntitys(param);
                processInstockProductList.forEach(item -> {
                    String key = isTransfer ? item.getProductId().toString() : item.getProductId() + "_" + item.getRefProductId();
                    Double num = processNumMap.getOrDefault(key, 0D);
                    num = Arith.add(num, item.getProductNum());
                    processNumMap.put(key, num);
                });
            }

            Iterator<BusinessProductEntity> iterator = businessProductEntityList.iterator();
            while (iterator.hasNext()){
                BusinessProductEntity entity = iterator.next();
                String key = isTransfer ? entity.getProductId().toString() : entity.getProductId() + "_" + entity.getId();
                Double num = entity.getProductNum();
                if (processNumMap.containsKey(key)){
                    if (num <= processNumMap.get(key)){
                        iterator.remove();
                    }else {
                        entity.setProductNum(Arith.sub(num,processNumMap.get(key)));
                    }
                }
            }
            if (businessProductEntityList.isEmpty() && needThrow) {
                throw new XbbException(InstockErrorCodeEnum.API_ERROR_210045);
            }
        }
        Iterator<BusinessProductEntity> it = businessProductEntityList.iterator();
        while (it.hasNext()){
            BusinessProductEntity entity = it.next();
            Long productId = entity.getProductId();
            Long id = entity.getId();
            String key;
            if (needMerge) {
                key = productId.toString();
            } else {
                key = productId + "_" + id;
                entity.setRefProductId(id);
            }
            Double num = entity.getProductNum();
            if (businessNumMap.containsKey(key)){
                if (num <= businessNumMap.get(key)){
                    if (Objects.equals(type, InstockTypeEnum.FINSHED_PRODUCT_INSTOCK.getCode())) {
                        entity.setProductNum(0D);
                    } else {
                        it.remove();
                    }
                }else {
                    entity.setProductNum(Arith.sub(num,businessNumMap.get(key)));
                }
            }
            if (Objects.nonNull(entity.getBusinessUnit())) {
                ProductEntityExt productEntityExt = productMap.get(productId);
                boolean enableSerial = false;
                if (Objects.nonNull(productEntityExt) && Objects.nonNull(productEntityExt.getData())) {
                     enableSerial = Objects.equals(productEntityExt.getData().getInteger(ProductEnum.ENABLE_SERIAL_NUMBER.getAttr()), 1);
                }
                ProductFieldPojo stockFieldPojo = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_STOCK,ProductEnum.STOCK.getAttr(), corpid);
                if (!enableSerial && Arith.round(Arith.div(entity.getProductNum(), entity.getRate()), stockFieldPojo.getAccuracy()) != BasicConstant.ZERO_DOUBLE) {
                    entity.setProductNum(Arith.div(entity.getProductNum(), entity.getRate()));
                    entity.setProductUnit(entity.getBusinessUnit().toString());
                    JSONObject priceData = entity.getPriceData();
                    if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                        entity.setPrice(priceData.containsKey(SelectProductEnum.SELLING_PRICE.getAttr()) ? priceData.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()) : priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                        entity.setHistoricalPrice(priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                        entity.setCost(priceData.getDouble(SelectProductEnum.COST.getAttr()));
                    }
                } else {
                    entity.setBusinessUnit(Long.parseLong(entity.getProductUnit()));
                    entity.setRate(1D);
                }
            }

        }

        return businessProductEntityList;
    }


    /**
     * 入库单获取退货退款未入库(特殊)
     * @param corpid
     * @param refId
     * @param type
     * @return
     */
    public Map<String,Double> getRefundUnInstockProduct(String corpid, Long refId, Integer type, boolean needMerge) throws XbbException {
        return saasProductHelp.getRefundUnInstockProduct(corpid ,refId, type, needMerge);
    }



    /**
     * 查询未出库产品
     * @param corpid
     * @param refId
     * @param type
     * @return
     * @throws XbbException
     */
    public List<BusinessProductEntity> searchUnOutstockProduct(String corpid, Long refId, Integer type, boolean needThrow) throws XbbException {
        List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.getUpStreamProduct(corpid,type,refId);
        boolean needMerge = false;
        List<Long> productIdList = new ArrayList<>();
        for (OutstockProductEntity entity : outstockProductEntityList){
            if (Objects.isNull(entity.getRefProductId())) {
                needMerge = true;
                break;
            }
        }
        Map<String,Double> businessNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity entity : outstockProductEntityList){
            if (needMerge) {
                Double num = businessNumMap.getOrDefault(entity.getProductId().toString(),0D);
                num = Arith.add(entity.getProductNum(), num);
                businessNumMap.put(entity.getProductId().toString(),num);
            } else {
                Double num = entity.getProductNum();
                String key = entity.getProductId() + "_" + entity.getRefProductId();
                businessNumMap.put(key,Arith.add(businessNumMap.getOrDefault(key,0D), num));
            }
        }

        List<BusinessProductEntity> businessProductEntityList = relativeProductHelp.getOutstockRelyBusinessProduct(corpid, refId, type, needMerge);
        businessProductEntityList.forEach(businessProductEntity -> {
            if (Objects.nonNull(businessProductEntity)) {
                productIdList.add(businessProductEntity.getProductId());
            }
        });
        Map<Long, ProductEntityExt> productMap = new HashMap<>(1 << 1);
        if (CollectionsUtil.isNotEmpty(productIdList)) {
            productMap = productModel.getProductMapByIds(corpid, productIdList, DelEnum.NORMAL.getDel(), Arrays.asList(StringConstant.SAAS_LINK_BUSINESS_ID, ProductEnum.getAttrConnectData(ProductEnum.ENABLE_SERIAL_NUMBER)));
        }
        // TODO 审批中数据校验 + 抛出错误
        OutstockTypeEnum outstockTypeEnum = OutstockTypeEnum.getByCode(type);
        if (Objects.equals(outstockTypeEnum, OutstockTypeEnum.CONTRACT_OUTSTOCK) || Objects.equals(outstockTypeEnum, OutstockTypeEnum.WORK_ORDER_OUTSTOCK)) {
            Map<String,Double> processNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 是否开启了工作流
            boolean isOpenWorkflow = commonHelp.isOpenWorkFlow(corpid);
            if (!isOpenWorkflow) {
                List<PaasProcessRelatedDataEntity> processDataList = paasProcessRelatedDataModel.getByRefIdAndBusinessType(refId, outstockTypeEnum.getStockBusinessType(), corpid);
                processDataList.forEach(item -> {
                    String key = item.getFourthRefId() + "_" + item.getSecondRefId();
                    Double num = processNumMap.getOrDefault(key, 0D);
                    num = Arith.add(num, item.getValue());
                    processNumMap.put(key, num);
                });
            } else {
                List<PaasFormDataEntityExt> outstockList = outstockModel.findOutstockList(corpid, type, refId,
                        Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()), Arrays.asList(FieldTypeEnum.DATAID.getAlias()));
                List<Long> outstockIdIn = new ArrayList<>();
                outstockList.forEach(item -> outstockIdIn.add(item.getDataId()));

                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", corpid);
                param.put("refId", refId);
                param.put("type", type);
                param.put("del", 0);
                param.put("orderByStr", "sort");
                param.put("outstockIdIn", outstockIdIn);
                List<OutstockProductEntity> processInstockProductList = outstockProductModel.findEntitys(param);
                processInstockProductList.forEach(item -> {
                    String key = item.getProductId() + "_" + item.getRefProductId();
                    Double num = processNumMap.getOrDefault(key, 0D);
                    num = Arith.add(num, item.getProductNum());
                    processNumMap.put(key, num);
                });
            }

            Iterator<BusinessProductEntity> iterator = businessProductEntityList.iterator();
            while (iterator.hasNext()){
                BusinessProductEntity entity = iterator.next();
                String key = entity.getProductId() + "_" + entity.getId();
                Double num = entity.getProductNum();
                if (processNumMap.containsKey(key)){
                    if (num <= processNumMap.get(key)){
                        iterator.remove();
                    }else {
                        entity.setProductNum(Arith.sub(num,processNumMap.get(key)));
                    }
                }
            }
            if (businessProductEntityList.isEmpty() && needThrow) {
                // TODO 需要改提示信息
                throw new XbbException(InstockErrorCodeEnum.API_ERROR_210046);
            }
        }
        Iterator<BusinessProductEntity> it = businessProductEntityList.iterator();
        // 销售出库单查询是否可以超发出库
        boolean overOutstock = false;
        if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()) ) {
            ContractEntityExt contractEntity = contractModel.getByKey(refId, corpid);
            if (Objects.nonNull(contractEntity) && Objects.nonNull(contractEntity.getFormId())){
                FormConfigEntity overOutstockConfig = formConfigModel.getEntityByFormId(corpid, contractEntity.getFormId(), FormConfigEnum.CONTRACT_ALLOW_OUTSTOCK_PRODUCT_NUM_LARGER_SOLD.getConfig());
                overOutstock = Objects.nonNull(overOutstockConfig) && Objects.equals(overOutstockConfig.getConfigValue(), "1");
            }
        }
        while (it.hasNext()){
            BusinessProductEntity entity = it.next();
            Long productId = entity.getProductId();
            Long id = entity.getId();
            String key;
            if (needMerge) {
                key = productId.toString();
            } else {
                key = productId + "_" + id;
                entity.setRefProductId(id);
            }
            Double num = entity.getProductNum();
            if (businessNumMap.containsKey(key)){
                if (num <= businessNumMap.get(key)){
                    if (Objects.equals(type, OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode())) {
                        entity.setProductNum(0D);
                    } else if (overOutstock){
                        entity.setProductNum(0D);
                    } else {
                        it.remove();
                    }
                }else {
                    entity.setProductNum(Arith.sub(num,businessNumMap.get(key)));
                }
            }
            if (Objects.nonNull(entity.getBusinessUnit())) {
                ProductEntityExt productEntityExt = productMap.get(productId);
                boolean enableSerial = false;
                if (Objects.nonNull(productEntityExt) && Objects.nonNull(productEntityExt.getData())) {
                    enableSerial = Objects.equals(productEntityExt.getData().getInteger(ProductEnum.ENABLE_SERIAL_NUMBER.getAttr()), 1);
                }
                ProductFieldPojo stockFieldPojo = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_STOCK,ProductEnum.STOCK.getAttr(), corpid);
                if (!enableSerial && Arith.round(Arith.div(entity.getProductNum(), entity.getRate()), stockFieldPojo.getAccuracy()) != BasicConstant.ZERO_DOUBLE) {
                    entity.setProductNum(Arith.div(entity.getProductNum(), entity.getRate(), stockFieldPojo.getAccuracy()));
                    entity.setProductUnit(entity.getBusinessUnit().toString());
                    JSONObject priceData = entity.getPriceData();
                    if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                        entity.setPrice(priceData.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()));
                        entity.setHistoricalPrice(priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                        if (Objects.equals(type, OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())) {
                            entity.setCost(priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                        } else {
                            entity.setCost(priceData.getDouble(SelectProductEnum.COST.getAttr()));
                        }
                    }
                } else {
                    entity.setBusinessUnit(Long.parseLong(entity.getProductUnit()));
                    entity.setRate(1D);
                }
            }
        }
        return businessProductEntityList;
    }

    /**
     * 获取出库数量
     * @param corpid 公司id
     * @param refId 关联业务id
     * @param type 关联业务类型
     * @throws XbbException
     * @return 已出库数量
     */
    public Map<String,Double> getOutstockProduct(String corpid, Long refId,Integer type, Map<Long,String> pageProductMap) throws XbbException {
        return saasProductHelp.getOutstockProduct(corpid, refId, type, pageProductMap);
    }

    /**
     * 获取入库数量（包含审批中数量）
     * @param corpid 公司id
     * @param refId 关联业务id
     * @param type 关联业务类型
     * @throws XbbException
     * @return 已出库数量
     */
    public Map<String,Double> getInstockProduct(String corpid, Long refId,Integer type, Map<Long,String> pageProductMap) throws XbbException {
        return saasProductHelp.getInstockProduct(corpid, refId, type, pageProductMap);
    }



    /**
     * 退货退款校验未退产品
     * @param corpid
     * @param contractId
     * @param refundId
     * @return
     * @throws XbbException
     */
    public Map<String,Double> getContractUnRefund(String corpid, Long contractId, Long refundId, boolean needMerge) throws XbbException {
        return saasProductHelp.getContractUnRefund(corpid, contractId, refundId, needMerge);
    }

    /**
     * 退货退款关联单据产品检索
     * @param corpid 公司id
     * @param contractId 关联合同id
     * @param isOpenJxc 是否开启jxc
     * @param refundId 退货退款id，编辑有，新建null，校验时排除自身
     * @return
     * @throws XbbException
     */
    public List searchContractUnRefund(String corpid, Long contractId, boolean isOpenJxc, Long refundId) throws XbbException {
        return saasProductHelp.searchContractUnRefund(corpid, contractId, isOpenJxc, refundId);
    }

    /**
     * 上游单据产品数量 与 已出入库数量 的校验
     *
     * @param isOverOutstockOpen 超发出库
     * @param downstreamBusiness 下游单据产品数量
     * @param upstreamBusiness 上游单据产品数量
     * @param pageProductMap 名称对应map
     * @param errMsg 错误提示
     * @throws XbbException 错误提示 小于出入库数量
     * @return 以出入完成
     */
    public Boolean upstreamDocumentsProductNumLegalCheck(boolean isOverOutstockOpen, Map<String, Double> downstreamBusiness, Map<String, Double> upstreamBusiness, Map<Long, String> pageProductMap, String errMsg) throws XbbException {
       return ProductUtil.upstreamDocumentsProductNumLegalCheck(isOverOutstockOpen, downstreamBusiness, upstreamBusiness, pageProductMap, errMsg);
    }

    /**
     * 剩余未出入库数量 与 出入库数量 的校验
     * @param overOutstock 超发出库
     * @param unStockMap 剩余未出入库数量
     * @param productNumMap 当前出入库数量(页面上用户填写的数量)
     * @param pageProductMap 名称对应map
     * @param errMsg 错误提示
     * @throws XbbException 错误提示 大于未出入库数量
     */
    public void stockProductNumLegalCheck(boolean overOutstock, Map<String, Double> unStockMap, Map<String, Double> productNumMap, Map<Long, String> pageProductMap, String errMsg) throws XbbException {
        ProductUtil.stockProductNumLegalCheck(overOutstock, unStockMap, productNumMap, pageProductMap, errMsg);
    }

    /**
     * 产品出库仓库库存校验
     * @param corpid 公司id
     * @param productArray 产品
     * @param pageWarehouseId 如果productArray中没有仓库信息，则使用传入值
     * @param warehouseFromOut 仓库是否来自于产品外
     * @param outstockType
     * @throws XbbException 库存不存在或库存不足校验
     */
    public void warehouseProductNumLegalCheck(String corpid, JSONArray productArray, Long pageWarehouseId, boolean warehouseFromOut, Integer outstockType) throws XbbException {
        saasProductHelp.warehouseProductNumLegalCheck(corpid, productArray, pageWarehouseId, warehouseFromOut, outstockType);
    }


    /**
     * 采购退货未退产品
     * @param corpid
     * @param dataId
     * @return
     */
    public List<BusinessProductEntity> searchPurchaseUnRefund(String corpid,Long dataId) throws XbbException{
        //可以退货的最大采购产品
//        BoolQueryBuilder boolQueryBuilder = boolQuery();
//        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
//        boolQueryBuilder.filter(termQuery(InstockEnum.getEsAttr4Keyword(InstockEnum.TYPE),InstockTypeEnum.PURCHASE_INSTOCK.getCode()));
//        boolQueryBuilder.filter(termsQuery(InstockEnum.getEsAttr4Keyword(InstockEnum.REF_ID),Collections.singletonList(dataId)));
//        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
//        List<PaasFormDataEntity> paasFormDataEntityList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INSTOCK,boolQueryBuilder,PaasFormDataEntity.class,Collections.singletonList(FieldTypeEnum.DATAID.getAlias()));
//        List<Long> instockIdList = new ArrayList<>();
//        paasFormDataEntityList.forEach(item -> instockIdList.add(item.getDataId()));
        List<BusinessProductEntity> instockProductEntityList = new ArrayList<>();
        //采购入库产品
//        if (!instockIdList.isEmpty()){
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("del", 0);
//            param.put("instockIdIn", instockIdList);
        param.put("type",InstockTypeEnum.PURCHASE_INSTOCK.getCode());
        param.put("refId",dataId);
        instockProductEntityList = instockProductModel.findProductNum(param);
//        }
        //新老数据
        boolean isOld = true;
        if (!instockProductEntityList.isEmpty()){
            isOld = Objects.isNull(instockProductEntityList.get(0).getRefProductId());
        }
        //采购合同已存在的退货产品
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termQuery(ReturnedPurchaseEnum.getEsAttr4Keyword(ReturnedPurchaseEnum.PURCHASE_SHEET_ID),dataId));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        List<PaasFormDataEntity> returnedPurchaseList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_RETURNED_PURCHASE,boolQueryBuilder,PaasFormDataEntity.class,Collections.singletonList(FieldTypeEnum.DATAID.getAlias()));
        List<Long> returnedPurchaseIdList = new ArrayList<>();
        returnedPurchaseList.forEach(item -> returnedPurchaseIdList.add(item.getDataId()));
        Map<Long,Double> refundMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!returnedPurchaseIdList.isEmpty()){
            param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid",corpid);
            param.put("del",0);
            param.put("returnPurchaseIdIn",returnedPurchaseIdList);
            List<BusinessProductEntity> businessProductEntityList = returnedPurchaseProductModel.findProductNum(param);
            //老数据需要合并同种产品
            for (BusinessProductEntity entity : businessProductEntityList){
                Long key;
                if (isOld){
                    key = entity.getProductId();
                }else {
                    key = entity.getRefProductId();
                }
                Double num = refundMap.getOrDefault(key,0D);
                num += entity.getProductNum();
                refundMap.put(key,num);
            }
        }
        if (isOld){
            Map<Long,BusinessProductEntity> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (BusinessProductEntity entity : instockProductEntityList){
                if (productMap.containsKey(entity.getProductId())){
                    BusinessProductEntity businessProductEntity = productMap.get(entity.getProductId());
                    Double preNum = businessProductEntity.getProductNum();
                    Double prePrice = businessProductEntity.getCost();
                    Double nowNum = entity.getProductNum();
                    Double nowPrice = entity.getCost();
                    Double price = (preNum * prePrice + nowNum * nowPrice) / (preNum + nowNum);
                    Double num = preNum + nowNum;
                    businessProductEntity.setProductNum(num);
                    businessProductEntity.setCost(price);
//                    purchaseProductEntity.setMemo(memo);
                    productMap.put(entity.getProductId(),businessProductEntity);
                }else {
                    productMap.put(entity.getProductId(),entity);
                }
            }
            instockProductEntityList = new ArrayList<>(productMap.values());
        }
        //
        Iterator<BusinessProductEntity> iterator = instockProductEntityList.iterator();
        while (iterator.hasNext()){
            BusinessProductEntity entity = iterator.next();
            Long key;
            if (isOld){
                key = entity.getProductId();
            }else {
                key = entity.getId();
            }
            Double num = entity.getProductNum();
            if (refundMap.containsKey(key)) {
                if (num > refundMap.get(key)) {
                    entity.setProductNum(num - refundMap.get(key));
                } else {
                    iterator.remove();
                }
            }
        }
        return instockProductEntityList;
    }

    /**
     * 获取分仓库存信息map
     * @param productIdList 产品id
     * @param corpid 公司id
     * @return  Map<产品id,Map<仓库id,分仓库存成本信息>>
     * @throws XbbException
     */
    public Map<Long,Map<String,JSONObject>> getWarehouseMap(List<Long> productIdList,String corpid) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.PRODUCT_ID), productIdList));
        // 仓库库存表有全仓数据，不要查出来
        boolQueryBuilder.mustNot(termQuery(ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.WAREHOUSE_ID), 0L));
        boolQueryBuilder.filter(termQuery(ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.WAREHOUSE_CHECKED), 1));
        List<PaasFormDataEntity> list = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE, boolQueryBuilder, PaasFormDataEntity.class, Arrays.asList(ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.PRODUCT_ID), ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.WAREHOUSE_ID), ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.NUM), ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.COST), ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.WAREHOUSE_NAME)));
        if (list.isEmpty()){
            return new HashMap<>();
        }
        Map<Long, Map<String, JSONObject>> productMaps = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        Integer accuracy = costField.getAccuracy();
        List<ProductWarehouseEntity> productWarehouseEntities = transferSubFormHelper.transferFormDataToProductWarehouseList(list);
        for (ProductWarehouseEntity entity : productWarehouseEntities) {
            JSONObject data = new JSONObject();
            data.put(ProductEnum.STOCK.getSaasAttr(), entity.getNum());
            Double cost = attrDecimalPrecisionHelper.setPrecision(entity.getCost(),accuracy);
            data.put(ProductEnum.COST.getSaasAttr(), cost);
            data.put(ProductEnum.WAREHOUSE.getSaasAttr(), entity.getWarehouseName());
            Map<String, JSONObject> dataList = productMaps.getOrDefault(entity.getProductId(), new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
            dataList.put(entity.getWarehouseId().toString(), data);
            productMaps.put(entity.getProductId(), dataList);
        }
        return productMaps;
    }

    /**
     * 获取sku成本
     * @param dataIdList
     * @param corpid
     * @return
     */
    public Map<Long,Double> getSkuCost(List<Long> dataIdList, String corpid) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),dataIdList));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,PaasFormDataEntityExt.class,Arrays.asList(FieldTypeEnum.DATAID.getAlias(),ProductEnum.getAttrConnectData(ProductEnum.COST)));
        Map<Long,Double> costMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        Integer accuracy = costField.getAccuracy();
        paasFormDataEntityExtList.forEach(item -> costMap.put(item.getDataId(),attrDecimalPrecisionHelper.setPrecision(item.getData().getDouble(ProductEnum.COST.getAttr()),accuracy)));
        return costMap;
    }


    /**
     * 获取sku成本
     * @param dataIdList
     * @param corpid
     * @return
     */
    public Map<Object,Double> getAllSkuCost(List<Long> dataIdList, String corpid) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),dataIdList));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,PaasFormDataEntityExt.class,Arrays.asList(FieldTypeEnum.DATAID.getAlias(),ProductEnum.getAttrConnectData(ProductEnum.COST)));
        Map<Object,Double> costMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        Integer accuracy = costField.getAccuracy();
        paasFormDataEntityExtList.forEach(item -> costMap.put(item.getDataId(),attrDecimalPrecisionHelper.setPrecision(item.getData().getDouble(ProductEnum.COST.getAttr()),accuracy)));
        return costMap;
    }


    public Map<Long,Double> getSkuWarehouseCost(List<Long> dataIdList, Long warehouseId, String corpid,Map<Long,Double> costMap,Map<Long,Double> stockMap) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.PRODUCT_ID), dataIdList));
        boolQueryBuilder.filter(termQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_ID), warehouseId));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_CHECKED), 1));
        List<PaasFormDataEntity> productWarehouseEntityList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE,boolQueryBuilder,PaasFormDataEntity.class,Arrays.asList(ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.PRODUCT_ID), ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.COST), ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.NUM)));
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        ProductFieldPojo stockField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_STOCK,ProductEnum.STOCK.getAttr(), corpid);
        Integer accuracy = costField.getAccuracy();
        Integer stockAccuracy = stockField.getAccuracy();
        List<ProductWarehouseEntity> productWarehouseEntities = transferSubFormHelper.transferFormDataToProductWarehouseList(productWarehouseEntityList);
        for (ProductWarehouseEntity entity : productWarehouseEntities){
            costMap.put(entity.getProductId(),attrDecimalPrecisionHelper.setPrecision(entity.getCost(),accuracy));
            stockMap.put(entity.getProductId(),attrDecimalPrecisionHelper.setPrecision(entity.getNum(),stockAccuracy));
        }
        return costMap;
    }


    public JSONObject formatUnit(String corpid, String productUnit) throws XbbException {
        return saasFormHelp.formatUnit(corpid, productUnit);
    }

    public Map<Long,Double> getSkuPrice(List<Long> productIdList, String corpid) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),productIdList));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,PaasFormDataEntityExt.class,Arrays.asList(FieldTypeEnum.DATAID.getAlias(),ProductEnum.getAttrConnectData(ProductEnum.PRICE)));
        Map<Long,Double> priceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        paasFormDataEntityExtList.forEach(item -> priceMap.put(item.getDataId(), Objects.isNull(item.getData()) ? 0D: item.getData().getDouble(ProductEnum.PRICE.getAttr())));
        for (PaasFormDataEntityExt item : paasFormDataEntityExtList) {
            if (Objects.nonNull(item.getData()) && Objects.nonNull(item.getData().getDouble(ProductEnum.PRICE.getAttr()))) {
                priceMap.put(item.getDataId(), item.getData().getDouble(ProductEnum.PRICE.getAttr()));
            } else {
                priceMap.put(item.getDataId(), 0D);
            }
        }
        return priceMap;
    }

    public JSONArray getWarehouseObj(String corpid, Long dataId, Integer businessType,Boolean isInstock) throws XbbException{
        PaasFormDataEntityExt paasFormDataEntityExt = proGetHelp.getByKey(dataId, businessType, SaasMarkEnum.SAAS.getCode(), corpid);
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        JSONObject warehouseObj = new JSONObject();
        JSONObject data = paasFormDataEntityExt.getData();
        switch (xbbRefTypeEnum){
            case INVENTORY:
                warehouseObj.put("id",data.getLong(InventoryEnum.WAREHOUSE_ID.getAttr()));
                warehouseObj.put("name",data.getString(InventoryEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr()));
                break;
            case TRANSFER:
                if (isInstock){
                    warehouseObj.put("id",data.getLong(TransferEnum.INTO_WAREHOUSE_ID.getAttr()));
                    warehouseObj.put("name",data.getString(TransferEnum.INTO_WAREHOUSE_ID_LINKED_TEXT.getAttr()));
                }else {
                    warehouseObj.put("id",data.getLong(TransferEnum.OUT_WAREHOUSE_ID.getAttr()));
                    warehouseObj.put("name",data.getString(TransferEnum.OUT_WAREHOUSE_ID_LINKED_TEXT.getAttr()));
                }
                break;
            case PRODUCTION_ORDER:
                if (isInstock){
                    warehouseObj.put("id",data.getLong(ProductionOrderEnum.INTO_WAREHOUSE_ID.getAttr()));
                    warehouseObj.put("name",data.getString(ProductionOrderEnum.INTO_WAREHOUSE_ID_LINK_TEXT.getAttr()));
                }else {
                    warehouseObj.put("id",data.getLong(ProductionOrderEnum.OUT_WAREHOUSE_ID.getAttr()));
                    warehouseObj.put("name",data.getString(ProductionOrderEnum.OUT_WAREHOUSE_ID_LINK_TEXT.getAttr()));
                }
                break;
        }
        JSONArray jsonArray = new JSONArray();
        jsonArray.add(warehouseObj);
        return jsonArray;
    }

    /**
     * 字段可见
     * @param fieldAttrEntity 字段
     * @param dataId 数据id
     * @param creatorId 创建人
     * @param loginUser 登录人
     * @param corpid 公司id
     * @param businessType 业务类型
     * @return 是否可见 true可见；flase不可见
     */
    public Boolean attrCanSee(FieldAttrEntity fieldAttrEntity, Long dataId, String creatorId, UserVO loginUser, String corpid, int businessType) {
       return commonHelp.attrCanSee(fieldAttrEntity, dataId, creatorId, loginUser, corpid, businessType);
    }





    public Boolean productCostVisible(String corpid, UserVO loginUser) throws XbbException{
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        if (Objects.equals(costField.getVisible(),0)){
            return false;
        }else {
            FieldAttrEntity costFieldAttrEntity = new FieldAttrEntity();
            costFieldAttrEntity.setVisible(1);
            if (Objects.equals(costField.getVisibleScopeEnable(), 1)) {
                if (!costField.getVisibleScopeRule().getRelative().isEmpty()) {
                    //高级可见负责人、协同人、创建人存在
                    if (costField.getVisibleScopeRule().getDep().isEmpty() && costField.getVisibleScopeRule().getRole().isEmpty() && costField.getVisibleScopeRule().getUser().isEmpty()) {
                        //高级可见部门、角色、人员全为空，字段不可见
                        //取巧做法，不对当前人可见
                        VisibleRulePoJo visibleScopeRule = new VisibleRulePoJo();
                        visibleScopeRule.setType(1);
                        visibleScopeRule.setUser(Collections.singletonList(loginUser.getUserId()));
                        costFieldAttrEntity.setVisibleScopeRule(visibleScopeRule);
                    } else {
                        //高级可见部门、角色、人员存在任何一个，移除负责人、协同人、创建人
                        costField.getVisibleScopeRule().setRelative(new ArrayList<>());
                        costFieldAttrEntity.setVisibleScopeRule(costField.getVisibleScopeRule());
                    }
                }
                return attrCanSee(costFieldAttrEntity,null,null,loginUser,corpid,XbbRefTypeEnum.PRODUCT.getCode());
            }
        }
        return true;
    }

    /**
     * 已处理过高级权限的pojo,可见直接取visible
     * @param corpid
     * @param loginUser
     * @return
     */
    public ProductFieldPojo costFieldPojo(String corpid, UserVO loginUser) throws XbbException{
        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        if (Objects.equals(costField.getVisible(),0)){
            return costField;
        }else {
            FieldAttrEntity costFieldAttrEntity = new FieldAttrEntity();
            BeanUtil.copyProperties(costField, costFieldAttrEntity);
            if (Objects.equals(costField.getVisibleScopeEnable(), 1)) {
                if (!costField.getVisibleScopeRule().getRelative().isEmpty()) {
                    //高级可见负责人、协同人、创建人存在
                    if (costField.getVisibleScopeRule().getDep().isEmpty() && costField.getVisibleScopeRule().getRole().isEmpty() && costField.getVisibleScopeRule().getUser().isEmpty()) {
                        //高级可见部门、角色、人员全为空，字段不可见
                        //取巧做法，不对当前人可见
                        VisibleRulePoJo visibleScopeRule = new VisibleRulePoJo();
                        visibleScopeRule.setType(1);
                        visibleScopeRule.setUser(Collections.singletonList(loginUser.getUserId()));
                        costFieldAttrEntity.setVisibleScopeRule(visibleScopeRule);
                    } else {
                        //高级可见部门、角色、人员存在任何一个，移除负责人、协同人、创建人
                        costField.getVisibleScopeRule().setRelative(new ArrayList<>());
                        costFieldAttrEntity.setVisibleScopeRule(costField.getVisibleScopeRule());
                    }
                }
                costField.setVisible(attrCanSee(costFieldAttrEntity,null,null,loginUser,corpid,XbbRefTypeEnum.PRODUCT.getCode()) ? 1 : 0);
            }
        }
        return costField;
    }

    /**
     * 单据新建编辑，判断产品是否是新增的
     * @param businessProductId 关联产品表的主键id
     * @return true 是新增 false 是编辑
     */
    public boolean addProductFlag(Long businessProductId) {
        //兼容审批传的小于0,统一维护
        return businessProductId == null || businessProductId.equals(0L) || businessProductId < 0L;
    }

    public List<FieldAttrEntity> listProductLinkKeyField(FieldAttrEntity fieldAttrEntity) {
        return SaasLinkProductUtil.listProductLinkKeyField(fieldAttrEntity);
    }



    /**
     * 获取分仓成本信息或者批次信息
     * @param productArray
     * @param warehouseId
     * @param corpid
     * @param costMap
     * @return
     * @throws XbbException
     */
    public Map<Object,Double> getSkuWarehouseOrBatchCost(JSONArray productArray, Long warehouseId, String corpid, Map<Object,Double> costMap, Map<Object,Double> stockMap) throws XbbException {
        return productValidateHelp.getSkuWarehouseOrBatchCost(productArray, warehouseId, corpid, costMap, stockMap);
    }


    /**
     * 获取拼装好的batchKey
     * @param productId
     * @param warehouseId
     * @param batch
     * @param produceDate
     * @param guaranteePeriod
     * @return
     */
    public String getBatchKey(Long productId, Long warehouseId, String batch, Long produceDate, Long guaranteePeriod) {
        return BatchKeyHelp.getBatchKey(productId, warehouseId, batch, produceDate, guaranteePeriod);
    }

    /**
     * 获取分仓成本信息或者批次信息,仓库不同
     * @param productArray
     * @param corpid
     * @param costMap
     * @return
     * @throws XbbException
     */
    public void getSkuWarehouseOrBatchCost(JSONArray productArray, String corpid, Map<Object, Double> costMap, Map<Object, Double> stockMap) throws XbbException{

        List<String> batchList = new ArrayList<>();
        List<String> noBatchList = new ArrayList<>();
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject product = productArray.getJSONObject(i);
            Long pageProductId = product.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long warehouseId = product.getLong(SelectProductEnum.WAREHOUSE.getAttr());
            String batch = product.getString(SelectProductEnum.BATCH.getAttr());
            if (StringUtil.isNotEmpty(batch)) {
                Long guaranteePeriod = product.getLong(SelectProductEnum.GUARANTEE_PERIOD.getAttr()) == null ? 0L : product.getLong(SelectProductEnum.GUARANTEE_PERIOD.getAttr()) * TimeConstant.SECONDS_PER_DAY;
                batchList.add(getBatchKey(pageProductId, warehouseId, batch, product.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()), guaranteePeriod));
            }else {
                noBatchList.add(pageProductId + "_" + warehouseId);
            }
        }

        ProductFieldPojo costField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_COST,ProductEnum.COST.getAttr(), corpid);
        ProductFieldPojo stockField = saasFormHelp.getProductFieldPojo(RedisPrefixConstant.PRODUCT_STOCK,ProductEnum.STOCK.getAttr(), corpid);
        Integer accuracy = costField.getAccuracy();
        Integer stockAccuracy = stockField.getAccuracy();
        costMap.put("costField", accuracy.doubleValue());

        if (!noBatchList.isEmpty()) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("del", DelEnum.NORMAL.getDel());
            param.put("warehouseKeyIn", noBatchList);
            List<ProductWarehouseEntity> warehouseEntities = productWarehouseModel.findEntitysWithWarehouseChecked(param, 1);
            for (ProductWarehouseEntity item : warehouseEntities) {
                costMap.put(item.getWarehouseKey(), attrDecimalPrecisionHelper.setPrecision(item.getCost(), accuracy));
                stockMap.put(item.getWarehouseKey(), attrDecimalPrecisionHelper.setPrecision(item.getNum(), stockAccuracy));
            }
        }

        //获取批次库存
        if (!batchList.isEmpty()) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("del", DelEnum.NORMAL.getDel());
            param.put("batchKeyIn", batchList);
            List<ProductStockEntity> entitys = productStockModel.findEntitys(param);
            for (ProductStockEntity item : entitys) {
                costMap.put(item.getBatchKey(), attrDecimalPrecisionHelper.setPrecision(item.getCost(), accuracy));
                stockMap.put(item.getBatchKey(), attrDecimalPrecisionHelper.setPrecision(item.getNum(), stockAccuracy));
            }
        }
    }


    public void setBusinessUnit(JSONObject jsonObject, BusinessUnitProductEntity businessUnitProductEntity) {
        ProductUtil.setBusinessUnit(jsonObject, businessUnitProductEntity);
    }

}
